#define xuser mixc::powerful_cat
#include"algo/distinct.hpp"
#include"define/nullref.hpp"
#include"interface/ranger.hpp"
#include"interface/unified_seq.hpp"
#include"mixc.hpp"
#include"utils/array.hpp"
#include"utils/counter.hpp"

xinit(xuser::the_main){
    using namespace xuser;
    counter demo = 0;

    // 演示：去除重复元素，每种元素只保留一个
    {
        xhint(demo);

        auto buf    = array<i32, 32>{};
        auto ary    = make_array(1, 1, 2, 3, 3, 2, 1);

        // 返回值是一个 unified_seq<T> 类型，是指向 buf 的一个弱指针结构
        // unified_seq<T> 可能是 ranger<T> 也可能是 seqptr<T>
        // unified_seq<T> 会优先选 seqptr<T>，因为它访问性能和裸指针想当
        // 如果 buf 中的元素在地址上不是完全连续的（也就是无法通过 buf 给出的一个首地址 + 偏移的方式访问任意元素）
        // 但支持 operator[]() 重载返回元素，那么它只能匹配 ranger<T>
        auto result = distinct(ary, 
            // 返回值需要是引用类型，通用的写法可以使用 auto & 作为返回值类型
            // 避免使用值传递，导致写入的是副本缓冲区，而且该缓冲区在回调时就提前析构了
            // 如果你确保缓冲区大小足够，那么参数 length 是无关紧要的
            [&](uxx) -> auto & {
                return buf;
            }

            // 也可以这么写，不够简洁，但返回值的类型可以一眼看出来
            /*
            [&](uxx length) -> array<i32, 32> & {
                return buf;
            }
            */

            // 返回值还支持显式的 unified_seq 类型
            // 但无论怎样，回调内部最终都会自己转换成匹配的 unified_seq
            // 返回值也是对应的 unified_seq 类型，而不是 buf 的类型
            /*
            [&](uxx length) -> unified_seq<decltype(buf)> {
                if (length > buf.length()){
                    return {};
                }
                return buf;
            }
            */

            // 接上
            // 也支持这样的写法
            /*
            [&](uxx length) -> auto & {
                if (length > buf->length){
                    return nullref.as<decltype(buf)>();

                    // 注意：
                    // 直接返回 nullref 就不行，因为 nullref 和 buf 是两个不一样的类型，
                    // auto & 无法正常推断返回值类型
                    // 需要将 nullref 转成 buf 类型
                }
                return buf;
            }
            */
        );

        // 依次打印 1, 2, 3
        result.foreach([](i32 const & v){
            xhint(v);
        });
    }
};
